"""
证书服务
封装证书申请、管理的业务逻辑
"""
import logging
from typing import List, Dict, Optional
from datetime import datetime, timedelta
from bson import ObjectId
from motor.motor_asyncio import AsyncIOMotorDatabase

from services.acme_client import ACMEClient
from utils.crypto import crypto_service
from models.certificate import CertificateStatus

logger = logging.getLogger(__name__)


class CertificateService:
    """证书服务"""
    
    @staticmethod
    async def apply_certificate_auto(
        db: AsyncIOMotorDatabase,
        cert_id: str,
        domains: List[str],
        ca_provider: str,
        contact_email: str,
        algorithm: str = "RSA"
    ) -> Dict:
        """
        自动申请证书（需要 DNS API 支持）
        
        Args:
            db: 数据库连接
            cert_id: 证书 ID
            domains: 域名列表
            ca_provider: CA 提供商
            contact_email: 联系邮箱
            algorithm: 证书算法
        
        Returns:
            申请结果
        """
        try:
            # 更新状态为处理中
            await db.certificates.update_one(
                {"_id": ObjectId(cert_id)},
                {"$set": {"status": CertificateStatus.PENDING.value}}
            )
            
            # 创建 ACME 客户端
            acme_client = ACMEClient(
                ca_provider=ca_provider,
                contact_email=contact_email
            )
            
            # DNS 记录回调（需要用户实现 DNS API）
            async def dns_callback(dns_records):
                # 保存 DNS 验证记录到数据库
                await db.certificates.update_one(
                    {"_id": ObjectId(cert_id)},
                    {"$set": {"dns_validation_records": dns_records}}
                )
                
                # TODO: 调用 DNS API 添加 TXT 记录
                # 这里需要根据用户的 DNS 提供商实现
                logger.warning("自动 DNS 添加未实现，请手动添加 DNS 记录")
            
            # 申请证书
            result = await acme_client.issue_certificate(
                domains=domains,
                algorithm=algorithm,
                dns_records_callback=dns_callback
            )
            
            if result["status"] == "issued":
                # 加密私钥
                encrypted_key = crypto_service.encrypt_private_key(result["private_key_pem"])
                
                # 计算 TTL 删除时间
                cert = await db.certificates.find_one({"_id": ObjectId(cert_id)})
                ttl_deletion_at = None
                if not cert.get("auto_renew"):
                    ttl_deletion_at = result["expires_at"] + timedelta(days=732)
                
                # 更新证书信息
                await db.certificates.update_one(
                    {"_id": ObjectId(cert_id)},
                    {"$set": {
                        "cert_fullchain_pem": result["cert_fullchain_pem"],
                        "key_encrypted": encrypted_key,
                        "expires_at": result["expires_at"],
                        "issued_at": datetime.utcnow(),
                        "ttl_deletion_at": ttl_deletion_at,
                        "status": CertificateStatus.ISSUED.value,
                        "updated_at": datetime.utcnow()
                    }}
                )
                
                logger.info(f"✅ 证书申请成功: {cert_id}")
                return {"status": "success", "message": "证书申请成功"}
            else:
                # 返回 DNS 记录，等待手动验证
                return result
        
        except Exception as e:
            logger.error(f"证书申请失败: {str(e)}")
            
            # 更新状态为失败
            await db.certificates.update_one(
                {"_id": ObjectId(cert_id)},
                {"$set": {
                    "status": CertificateStatus.FAILED.value,
                    "updated_at": datetime.utcnow()
                }}
            )
            
            raise
    
    @staticmethod
    async def get_dns_validation_info(
        domains: List[str],
        ca_provider: str,
        contact_email: str
    ) -> List[Dict]:
        """
        获取 DNS 验证信息（不实际申请证书）
        
        Args:
            domains: 域名列表
            ca_provider: CA 提供商
            contact_email: 联系邮箱
        
        Returns:
            DNS 验证记录列表
        """
        try:
            # 创建 ACME 客户端
            acme_client = ACMEClient(
                ca_provider=ca_provider,
                contact_email=contact_email
            )
            
            # 初始化
            await acme_client.initialize()
            
            # 创建订单
            order, dns_records = await acme_client.create_order(domains)
            
            return dns_records
        
        except Exception as e:
            logger.error(f"获取 DNS 验证信息失败: {str(e)}")
            raise
    
    @staticmethod
    async def verify_and_issue(
        db: AsyncIOMotorDatabase,
        cert_id: str,
        domains: List[str],
        ca_provider: str,
        contact_email: str,
        algorithm: str = "RSA"
    ) -> Dict:
        """
        验证 DNS 并签发证书
        
        Args:
            db: 数据库连接
            cert_id: 证书 ID
            domains: 域名列表
            ca_provider: CA 提供商
            contact_email: 联系邮箱
            algorithm: 证书算法
        
        Returns:
            签发结果
        """
        try:
            # 获取证书记录
            cert = await db.certificates.find_one({"_id": ObjectId(cert_id)})
            if not cert:
                raise ValueError("证书不存在")
            
            dns_records = cert.get("dns_validation_records", [])
            if not dns_records:
                raise ValueError("没有找到 DNS 验证记录")
            
            # 创建 ACME 客户端
            acme_client = ACMEClient(
                ca_provider=ca_provider,
                contact_email=contact_email
            )
            
            # 初始化
            await acme_client.initialize()
            
            # 创建新订单
            order, new_dns_records = await acme_client.create_order(domains)
            
            # 验证 DNS
            await acme_client.verify_dns_challenge(order, new_dns_records)
            
            # 完成订单并获取证书
            cert_pem, key_pem, expires_at = await acme_client.finalize_order(
                order, domains, algorithm
            )
            
            # 加密私钥
            encrypted_key = crypto_service.encrypt_private_key(key_pem)
            
            # 计算 TTL 删除时间
            ttl_deletion_at = None
            if not cert.get("auto_renew"):
                ttl_deletion_at = expires_at + timedelta(days=732)
            
            # 更新证书信息
            await db.certificates.update_one(
                {"_id": ObjectId(cert_id)},
                {"$set": {
                    "cert_fullchain_pem": cert_pem,
                    "key_encrypted": encrypted_key,
                    "expires_at": expires_at,
                    "issued_at": datetime.utcnow(),
                    "ttl_deletion_at": ttl_deletion_at,
                    "status": CertificateStatus.ISSUED.value,
                    "updated_at": datetime.utcnow()
                }}
            )
            
            logger.info(f"✅ 证书签发成功: {cert_id}")
            return {
                "status": "success",
                "message": "证书签发成功",
                "expires_at": expires_at
            }
        
        except Exception as e:
            logger.error(f"证书签发失败: {str(e)}")
            
            # 更新状态为失败
            await db.certificates.update_one(
                {"_id": ObjectId(cert_id)},
                {"$set": {
                    "status": CertificateStatus.FAILED.value,
                    "updated_at": datetime.utcnow()
                }}
            )
            
            raise

